/**
 * @(#)ThirdTaskServiceImpl.java 2017年7月28日
 * Copyright(C) 2017 ZHEXIN IT CO.,LTD. All rights reserved.
 */
package org.jsbd.boss.service.impl;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.jsbd.boss.bto.HttpReq;
import org.jsbd.boss.bto.HttpResult;
import org.jsbd.boss.bto.SdkSmsVo;
import org.jsbd.boss.bto.SmsProtocol;
import org.jsbd.boss.common.ConstantsCmp;
import org.jsbd.boss.common.redis.RedisClient;
import org.jsbd.boss.domian.InterceptInfo;
import org.jsbd.boss.domian.IpRange;
import org.jsbd.boss.domian.channel.BaseResultVo;
import org.jsbd.boss.domian.channel.HefenTaskVo;
import org.jsbd.boss.domian.channel.ThirdSmsConfig;
import org.jsbd.boss.domian.channel.ThirdSmsTaskVo;
import org.jsbd.boss.enums.SmsSendTypeEnum;
import org.jsbd.boss.enums.TaskStatusEnum;
import org.jsbd.boss.service.ClientManager;
import org.jsbd.boss.service.IInterceptInfoService;
import org.jsbd.boss.service.IProvinceService;
import org.jsbd.boss.service.IThirdSmsConfigService;
import org.jsbd.boss.service.IThirdTaskService;
import org.jsbd.boss.util.AndroidBase64;
import org.jsbd.boss.util.CacheKey;
import org.jsbd.boss.util.DMChannelSmsUtil;
import org.jsbd.boss.util.DateUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.connection.ReturnType;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONObject;
import com.qy.recphone.service.IRecPhoneService;

/**
 * 第三方任务
 *
 * @author <a href="mailto:xupengcheng@zhexinit.com" >徐鹏程</a>
 * @version 1.0.0
 */
@Service
public class ThirdTaskServiceImpl implements IThirdTaskService {
    public static final Logger LOGGER = LoggerFactory.getLogger(ThirdTaskServiceImpl.class);

    @Resource
    private CacheParamManager cacheParamManager;

    @Resource
    private RedisClient redisClient;

    @Resource
    private IProvinceService provinceService;

    @Resource
    private IRecPhoneService recPhoneService;

    @Resource
    private IInterceptInfoService interceptInfoService;

    @Resource
    private IThirdSmsConfigService thirdSmsConfigService;

    /*
     * (non-Javadoc)
     *
     * @see org.jsbd.boss.service.IThirdTaskService#addTask(java.lang.String,
     * java.lang.Integer)
     */
    @Override
    public BaseResultVo addTask(HttpResult httpResult) {
        IpRange ipRange = provinceService.getProvinceInfo(httpResult.getImsi(), httpResult.getPhoneNum());
        int provinceId = -1;
        if (ipRange != null) {
            provinceId = ipRange.getProvinceId();
        }
        if (provinceId != -1) {
            return addTask(httpResult, provinceId);
        }
        return null;
    }

    /*
     * (non-Javadoc)
     *
     * @see
     * org.jsbd.boss.service.IThirdTaskService#addTask(org.jsbd.boss.bto.HttpResult
     * , java.lang.Integer)
     */
    @Override
    public BaseResultVo addTask(HttpResult httpResult, Integer provinceId) {
        BaseResultVo resultVo = new BaseResultVo();
        try {
            SmsProtocol thirdSmsTask = addThirdSmsTask(httpResult);
            if (thirdSmsTask != null) {
                List<HttpReq> list = thirdSmsTask.getList();
                if (list != null && !list.isEmpty()) {
                    LOGGER.warn("获取第三方任务 {} {}", httpResult.getImsi(), list.get(0).getId());
                } else {
                    LOGGER.warn("获取第三方任务 {}", httpResult.getImsi(), thirdSmsTask.toString());
                }
                resultVo.setData(thirdSmsTask);
            } else {
                resultVo.setStatus(TaskStatusEnum.FAIL.getType());
                resultVo.setMessage("没有可用第三方任务");
                LOGGER.warn("没有可用第三方任务 {}", new String[]{httpResult.getImsi()});
            }
        } catch (Exception e) {
            LOGGER.error("第三方任务获取失败 {} {} ", httpResult.getImsi(), e);
            resultVo.setStatus(TaskStatusEnum.FAIL.getType());
        }
        return resultVo;
    }

    private String getSendSmsField(String mobile) {
        return mobile + "sendsms";
    }

    @Override
    public void sendSms(String code, String mobile) {
        String mobileRecordKey = CacheKey.T_S_M_R + "third" + code;
        LOGGER.warn("短信发送标记 {} {}", code, mobile);
        redisClient.evalHset(mobileRecordKey, getSendSmsField(mobile), "1");
    }


    private SmsProtocol addThirdSmsTask(HttpResult httpResult) {
        String imsi = httpResult.getImsi();
        String mobile = httpResult.getPhoneNum();
        if (StringUtils.isBlank(mobile)) {
            mobile = recPhoneService.getPhoneByImsi(imsi);
        }
        SmsProtocol smsProtocol = null;
        if (StringUtils.isNotBlank(mobile)) {
            mobile = mobile.replace("+86", "");
            List<ThirdSmsConfig> list = thirdSmsConfigService.selectAllThirdSmsConfigCache();
            // 优先做咪咕注册的
            if (list != null && list.size() > 0) {
                Integer carrier = ClientManager.checkImsi(imsi);
                if (carrier == -1) {
                    return null;
                }
                Iterator<ThirdSmsConfig> smsIterator = list.iterator();
                while (smsIterator.hasNext()) {
                    ThirdSmsConfig smsConfig = smsIterator.next();
                    String code = smsConfig.getCode();
                    // 咪咕注册任务
                    if (code.equalsIgnoreCase("miguregister")) {
                        smsProtocol = initSmsProtocol(smsConfig, carrier, httpResult, mobile, imsi);
                        if (smsProtocol != null) {
                            return smsProtocol;
                        } else {
                            smsIterator.remove();
                            break;
                        }
                    }
                }
                for (ThirdSmsConfig smsConfig : list) {
                    smsProtocol = initSmsProtocol(smsConfig, carrier, httpResult, mobile, imsi);
                    if (smsProtocol != null) {
                        return smsProtocol;
                    }
                }
            }
        }
        return smsProtocol;
    }

    private SmsProtocol initSmsProtocol(ThirdSmsConfig smsConfig, Integer carrier, HttpResult httpResult, String mobile, String imsi) {
        SmsProtocol smsProtocol = null;
        Integer taskType = smsConfig.getTaskType();
        String carriers = smsConfig.getCarrier();
        if (StringUtils.isBlank(carriers)) {
            carriers = "0,1,2";
        }
        String channelName = smsConfig.getChannelName();
        String channelId = httpResult.getChannelId();
        if (channelId == null) {
            channelId = "";
        }
        if (StringUtils.isNotBlank(channelName)) {
            // 限制渠道
            if (channelName.toLowerCase().indexOf(channelId.toLowerCase()) < 0) {
                return null;
            }
        }
        String filterChannel = smsConfig.getFilterChannel();
        if (StringUtils.isNotBlank(filterChannel)) {
            // 过滤渠道
            if (filterChannel.toLowerCase().indexOf(channelId.toLowerCase()) >= 0) {
                return null;
            }
        }

        if (carriers.indexOf(carrier.toString()) >= 0) {
            if (taskType != null) {
                switch (taskType) {
                    case 0:
                        String andriodId = httpResult.getAndroidId();
                        if (StringUtils.isBlank(andriodId)) {
                            andriodId = UUID.randomUUID().toString().replace("-", "").substring(0, 16);
                        }
                        ThirdSmsTaskVo taskVo = new ThirdSmsTaskVo();
                        taskVo.setAndriodId(andriodId);
                        taskVo.setImsi(imsi);
                        taskVo.setMobile(mobile);
                        taskVo.setCreateTime(System.currentTimeMillis());
                        smsProtocol = noNeedSendSms(smsConfig, taskVo);
                        if (smsProtocol != null) {
                            return smsProtocol;
                        } else {
                            break;
                        }
                    case 1:
                        smsProtocol = needSendSms(smsConfig, mobile, imsi);
                        if (smsProtocol != null) {
                            return smsProtocol;
                        } else {
                            break;
                        }
                    case 2:
                        smsProtocol = onlySendSms(smsConfig, mobile, imsi);
                        if (smsProtocol != null) {
                            LOGGER.warn("第三方短信下发短信 {} {} {}", new String[]{mobile, smsConfig.getCode(), JSONObject.toJSONString(smsProtocol)});
                            return smsProtocol;
                        } else {
                            break;
                        }
                    default:
                        break;
                }
            }
        }
        return null;
    }


    /**
     * 只发短信
     *
     * @param smsConfig
     * @param mobile
     * @param imsi
     * @return
     */
    private SmsProtocol onlySendSms(ThirdSmsConfig smsConfig, String mobile, String imsi) {
        String size = "10";
        Object queueSize = cacheParamManager.getParamValue(CacheKey.THIRD_SMS_QUEUE_SIZE);
        if (queueSize != null) {
            size = queueSize.toString();
        }
        String apk = "third" + smsConfig.getCode();
        String mobileRecordKey = CacheKey.T_S_M_R + apk;
        String mobileQueueKey = CacheKey.T_S_M_L + apk;
        ThirdSmsTaskVo taskVo = new ThirdSmsTaskVo();
        taskVo.setImsi(imsi);
        taskVo.setMobile(mobile);
        taskVo.setCreateTime(System.currentTimeMillis());
        Long result = (Long) redisClient.eval(initOnlySendSmsTaskLua(), ReturnType.VALUE, new String[]{mobileRecordKey, imsi
                , mobileQueueKey, taskVo.toString(), size
                , getSendSmsField(mobile)});
        //仅仅记录手机号
        if (result != null && result.intValue() == 1) {
            redisClient.put(CacheKey.IMSI_MOBILE + imsi, mobile, 900);
            return null;
        } else if (result != null && result.intValue() == 2) {
            //发送短信
            SmsProtocol smsProtocol = initSendSmsProtocol(imsi, "1", smsConfig);
            return smsProtocol;
        } else if (result.intValue() == 4) {
            LOGGER.warn("号码已经下发过 或者队列已经满了 {} {} {} ", new String[]{mobile, imsi, apk});
        }
        return null;
    }

    private String initOnlySendSmsTaskLua() {
        StringBuilder sb = new StringBuilder();
        sb.append(" if redis.call('HEXISTS', KEYS[1], KEYS[6]) == 1 then redis.call('hdel',KEYS[1], KEYS[6]) return 2 ");
        sb.append(" else");
        sb.append(" if redis.call('llen', KEYS[3])<tonumber(KEYS[5]) and redis.call('HEXISTS', KEYS[1], KEYS[2]) == 0");
        sb.append(" then");
        sb.append(" redis.call('lPush', KEYS[3], KEYS[4])");
        sb.append(" redis.call('hset', KEYS[1], KEYS[2],1)");
        sb.append(" return 1");
        sb.append(" else return 4 end end");
        return sb.toString();
    }

    /**
     * needSendSms:sdk发送短信内容
     *
     * @param smsConfig
     * @param mobile
     * @param imsi
     * @return
     * @author <a href="mailto:xupengcheng@zhexinit.com" >徐鹏程</a>
     */
    private SmsProtocol needSendSms(ThirdSmsConfig smsConfig, String mobile, String imsi) {
        String apk = "third" + smsConfig.getCode();
        String taskRecordKey = CacheKey.THIRD_TASK_HASH + smsConfig.getCode() + DateUtil.getDaysOfTime();
        String mobileRecordKey = CacheKey.T_S_M_R + apk;
        String lockKey = CacheKey.T_S_M_R + apk + imsi;
        String imsiLockTime = "900";
        Object lockTime = cacheParamManager.getParamValue(CacheKey.THIRD_SMS_LOCK_TIME);
        if (lockTime != null) {
            imsiLockTime = lockTime.toString();
        }
        String taskNum = Integer.MAX_VALUE + "";
        if (smsConfig.getTaskNum() != null) {
            taskNum = smsConfig.getTaskNum().toString();
        }
        Long result = (Long) redisClient.eval(initSendSmsTaskLua(), ReturnType.VALUE, new String[]{taskRecordKey, mobileRecordKey, imsi, lockKey, taskNum, imsiLockTime});
        if (result != null && result.intValue() == 1) {
            redisClient.put(CacheKey.IMSI_MOBILE + imsi, mobile, 900);
            return initSendSmsProtocol(imsi, "1", smsConfig);
        } else if (result.intValue() == 4) {
            LOGGER.warn("号码已经下发过 {} {} {} ", new String[]{mobile, imsi, apk});
        } else if (result.intValue() == 5) {
            LOGGER.warn("队列满了 {} {} {} ", new String[]{mobile, imsi, apk});
        } else if (result.intValue() == 3) {
            LOGGER.warn("15分钟下发过 {} {} {} ", new String[]{mobile, imsi, apk});
        }
        return null;
    }

    /**
     * noNeedSendSms:不需要发短信 只需要下发手机号码 拦截验证码
     *
     * @param smsConfig
     * @return
     * @author <a href="mailto:xupengcheng@zhexinit.com" >徐鹏程</a>
     */
    private SmsProtocol noNeedSendSms(ThirdSmsConfig smsConfig, ThirdSmsTaskVo taskVo) {
        String size = "10";
        Object queueSize = cacheParamManager.getParamValue(CacheKey.THIRD_SMS_QUEUE_SIZE);
        if (queueSize != null) {
            size = queueSize.toString();
        }
        String imsiLockTime = "900";
        Object lockTime = cacheParamManager.getParamValue(CacheKey.THIRD_SMS_LOCK_TIME);
        if (lockTime != null) {
            imsiLockTime = lockTime.toString();
        }
        String mobile = taskVo.getMobile();
        String imsi = taskVo.getImsi();
        String apk = "third" + smsConfig.getCode();
        String mobileRecordKey = CacheKey.T_S_M_R + apk;
        String mobileQueueKey = CacheKey.T_S_M_L + apk;
        String lockKey = CacheKey.T_S_M_R + apk + imsi;

        Long result = (Long) redisClient.eval(initThirdSmsTaskLua(), ReturnType.VALUE, new String[]{mobileRecordKey, imsi, lockKey, mobileQueueKey, taskVo.toString(), size, imsiLockTime});
        if (result != null && result.intValue() == 1) {
            redisClient.put(CacheKey.IMSI_MOBILE + imsi, mobile, 900);
            return initFilterSmsProtocol(imsi, apk, smsConfig.getSmsId().toString());
        } else if (result.intValue() == 4) {
            LOGGER.warn("号码已经下发过 {} {} {} ", new String[]{mobile, imsi, apk});
        } else if (result.intValue() == 5) {
            LOGGER.warn("队列满了 {} {} {} ", new String[]{mobile, imsi, apk});
        } else if (result.intValue() == 3) {
            LOGGER.warn("15分钟下发过 {} {} {} ", new String[]{mobile, imsi, apk});
        }
        return null;
    }

    private String initSendSmsTaskLua() {
        StringBuilder sb = new StringBuilder();
        sb.append(" redis.call('hincrby', KEYS[1], 'exectotal',0) local exectotal=redis.call('hget', KEYS[1], 'exectotal') ");
        sb.append(" if tonumber(exectotal)<tonumber(KEYS[5])");
        sb.append(" then ");
        sb.append(" local has=redis.call('HEXISTS', KEYS[2], KEYS[3])");
        sb.append(" if has == 0");
        sb.append(" then ");
        sb.append(" if redis.call('setnx',KEYS[4],1)==1 ");
        sb.append(" then ");
        sb.append(" redis.call('expire',KEYS[4],KEYS[6]) ");
        sb.append(" redis.call('hset', KEYS[2], KEYS[3],1)  ");
        sb.append(" redis.call('hincrby', KEYS[1], 'exectotal',1)  ");
        sb.append(" redis.call('expire',KEYS[1],86400) ");
        sb.append(" return 1 ");
        sb.append(" else return 3 end ");
        sb.append(" else return 4 end ");
        sb.append(" else return 5 end ");
        return sb.toString();
    }

    private SmsProtocol initSendSmsProtocol(String imsi, String sendType, ThirdSmsConfig smsConfig) {
        SdkSmsVo smsVo = new SdkSmsVo();
        String apk = "third" + smsConfig.getCode();
        String sendSms = smsConfig.getSendSms();
        String orderId = imsi + "_" + apk;
        smsVo.setPhone(smsConfig.getSendPhoneNum());
        smsVo.setSendType(sendType);
        if (sendType.equals(String.valueOf(SmsSendTypeEnum.TEXT.getType()))) {
            smsVo.setMessage(sendSms);
            smsVo.setSendPort("0");
        } else {
            smsVo.setSendPort("2000");
            if (sendSms != null) {
                smsVo.setMessage(AndroidBase64.encode(sendSms.getBytes()));
            }
        }
        smsVo.setSendCount("1");
        smsVo.setReSendCount("1");
        smsVo.setNeedSendSms("1");
        smsVo.setPaycode(apk);
        HttpReq hReq = DMChannelSmsUtil.flushChannel(ConstantsCmp.PROTOCOL_TYPE_SMS, orderId, smsVo);
        List<HttpReq> taskList = new ArrayList<HttpReq>();
        taskList.add(hReq);
        return DMChannelSmsUtil.wrapSmsProtocol(taskList);

    }

    /**
     * initFilterSmsProtocol:拦截规则下发
     *
     * @param imsi
     * @param apk
     * @param smsId
     * @return
     * @author <a href="mailto:xupengcheng@zhexinit.com" >徐鹏程</a>
     */
    private SmsProtocol initFilterSmsProtocol(String imsi, String apk, String smsId) {
        SdkSmsVo smsVo = new SdkSmsVo();
        String orderId = imsi + "_" + apk;
        smsVo.setPhone("106581061");
        Integer sendType = SmsSendTypeEnum.DATA.getType();
        smsVo.setSendType(sendType.toString());
        smsVo.setSendPort("2000");
        List<InterceptInfo> inteceptList = new ArrayList<InterceptInfo>();
        inteceptList.add(interceptInfoService.selectInterceptOfId(smsId));
        smsVo.setInteceptList(inteceptList);
        smsVo.setSendCount("1");
        smsVo.setReSendCount("0");
        smsVo.setNeedSendSms("0");
        smsVo.setPaycode(apk);
        HttpReq hReq = DMChannelSmsUtil.flushChannel(ConstantsCmp.PROTOCOL_TYPE_SMS, orderId, smsVo);
        List<HttpReq> taskList = new ArrayList<HttpReq>();
        taskList.add(hReq);
        return DMChannelSmsUtil.wrapSmsProtocol(taskList);
    }

    private String initThirdSmsTaskLua() {
        StringBuilder sb = new StringBuilder();
        sb.append("local queueSize=redis.call('llen', KEYS[4])");
        sb.append(" if queueSize<tonumber(KEYS[6])");
        sb.append(" then");
        sb.append(" local has=redis.call('HEXISTS', KEYS[1], KEYS[2])");
        sb.append(" if has == 0");
        sb.append(" then");
        sb.append(" if redis.call('setnx',KEYS[3],1)==1");
        sb.append(" then");
        sb.append(" redis.call('expire',KEYS[3],KEYS[7])");
        sb.append(" redis.call('lPush', KEYS[4], KEYS[5])");
        sb.append(" return 1");
        sb.append(" else return 3 end");
        sb.append(" else return 4 end");
        sb.append(" else return 5 end");
        return sb.toString();

    }


}
